#include "base/function.hpp"
#include "base/mempool.h"
#include "base/log.h"

#include <memory.h>
#include <stdlib.h>
#include <iostream>

namespace net_tools::base{
using namespace detail;

#define to_char(x) reinterpret_cast<char*>(x)
#define to_memptr(x) reinterpret_cast<Memorypool_point*>(x)

Memorypool::Memorypool(size_t block_size,size_t block_number)
  :pmemory_data_(nullptr),
   pmemory_pool_(nullptr),
   block_number_(block_number),
   block_size_(block_size),
   block_size_move_(0),
   mutex_()
{
  Log::Init();
  while(block_size_){
    ++block_size_move_;
    block_size_ >>= 1;
  }
  --block_size_move_;
  NT_LOG_INFO << "block_size_move_: " << block_size_move_ << NT_LOG_ENDL;
  block_size_ = block_size;
  memory_pool_size_ = (block_number_ * (block_size_ + MEMORY_POOL_POINT_SIZE));
  memory_pool_data_size_ = block_number_ * block_size_;

  pmemory_pool_ = malloc(memory_pool_size_);
  pmemory_data_ = to_char(pmemory_pool_) + block_number_ * MEMORY_POOL_POINT_SIZE;
  if(pmemory_pool_ == nullptr){
    std::cout << "内存池初始错误 malloc错误!!!!!" << std::endl;
    exit(0);
  }else{
    memset(pmemory_pool_,0,memory_pool_size_);

    help_point_head_ = new Memorypool_point;
    help_point_back_ = new Memorypool_point;
    help_point_head_->next_ = help_point_back_;
    help_point_back_->before_ = help_point_head_;

    Memorypool_point* pfirst_memory_pool_point =
                Point_create(to_memptr(pmemory_pool_),memory_pool_data_size_); //初始化整个链表

    Point_insert(help_point_head_,pfirst_memory_pool_point); //将初始大区块插入链表中
    Point_back_create(pfirst_memory_pool_point);
    free_block_number_ = 1;
    pmemory_data_end_ = to_char(pmemory_data_) + memory_pool_data_size_;
    NT_LOG_INFO << "内存池初始成功 size:" << memory_pool_size_ << NT_LOG_ENDL;
  }
};
Memorypool::~Memorypool(){
  free(pmemory_pool_);
};

void* Memorypool::Get_memory_unlocked(size_t block_number){
  if(free_block_number_ == 0) [[unlikely]] return nullptr; //没有空block了
  Memorypool_point* tmp = help_point_head_->next_; //为第一个真实可用节点
  size_t need_size = block_number * block_size_;
  while(tmp->next_->size_ != 0){ //不等于最后的帮助节点
    if(tmp->size_ >= need_size)break; //该节点大小大于所需内存
    tmp = tmp->next_;
  }
  if(tmp->size_ < need_size) [[unlikely]] return nullptr; //head->next_为帮助节点且当前head小于size 申请失败

  if(tmp->size_ == need_size){ //相等 则不用分割
    Point_cut(tmp);
    Point_back_create(tmp);
    --free_block_number_;
  }else{
    //把多出来的块 建立记录块
    Memorypool_point* back = Point_create(to_char(tmp) + block_number * MEMORY_POOL_POINT_SIZE,tmp->size_ - need_size);
    //用back代替tmp
    back->before_ = tmp->before_;
    back->before_->next_ = back;
    back->next_ = tmp->next_;
    back->next_->before_ = back;
    if(back->size_ != block_size_)Point_back_create(back);
    Point_create(tmp,need_size);
  }
  return Change_block_to_data(tmp);
};
void* Memorypool::Get_memory_locked(size_t block_number){
  mutex_.Lock();
  if(free_block_number_ == 0) [[unlikely]] {
    mutex_.Unlock();
    return nullptr; //没有空block了
  }
  Memorypool_point* tmp = help_point_head_->next_; //为第一个真实可用节点
  size_t need_size = block_number * block_size_;
  while(tmp->next_->size_ != 0){ //不等于最后的帮助节点
    if(tmp->size_ >= need_size)break; //该节点大小大于所需内存
    tmp = tmp->next_;
  }
  if(tmp->size_ < need_size) [[unlikely]] {
    mutex_.Unlock();
    return nullptr; //head->next_为帮助节点且当前head小于size 申请失败
  }
  if(tmp->size_ == need_size){ //相等 则不用分割
    Point_cut(tmp);
    Point_back_create(tmp);
    --free_block_number_;
  }else{
    //把多出来的块 建立记录块
    Memorypool_point* back = Point_create(to_char(tmp) + block_number * MEMORY_POOL_POINT_SIZE,tmp->size_ - need_size);
    //用back代替tmp
    back->before_ = tmp->before_;
    back->before_->next_ = back;
    back->next_ = tmp->next_;
    back->next_->before_ = back;
    if(back->size_ != block_size_)Point_back_create(back);
    Point_create(tmp,need_size);
  }
  mutex_.Unlock();
  return Change_block_to_data(tmp);
};

void Memorypool::Free_memory_unlocked(void* paddress){
  if(paddress < pmemory_data_ || paddress > (to_char(pmemory_data_) + memory_pool_data_size_)) [[unlikely]] {
    NT_LOG_ERROR << "free memory 越界" << NT_LOG_ENDL;
    return;
  }

  Memorypool_point* block = to_memptr(Change_data_to_block(paddress));
  Memorypool_point* before = nullptr;
  Memorypool_point* next = nullptr;

  if(block != pmemory_pool_){ //如果不是队首 则有上一个节点
    before = to_memptr(to_char(block) - MEMORY_POOL_POINT_SIZE); //前一个节点尾部信息
    if(before->before_ != nullptr){ //如果前一个节点可以合并
      before = to_memptr(to_char(block) - (before->size_ >> block_size_move_)*MEMORY_POOL_POINT_SIZE);//头
      before->size_ += block->size_;
      block = before;
      Point_back_create(block);
    }else{
      before = nullptr;
    }
  }

  if(to_char(paddress) + block->size_ != pmemory_data_end_){ //如果不是最后一个
    next = to_memptr(to_char(block) + (block->size_ >> block_size_move_) * MEMORY_POOL_POINT_SIZE); //后一个节点信息
    if(next->next_ != nullptr){ //如果后一个节点可以合并 且不是帮助节点
      if(block->before_ != nullptr) { //如果和前一个节点合并过了 记录块整理好了
        block->size_ += next->size_;
        block->next_ = next->next_;
        block->next_->before_ = block;
        Point_back_create(block);
        Point_back_create(block->next_); //修改后面节点的尾部数据块 当后面节点不是帮助节点的时候
        --free_block_number_;
      }else{ //如果没有合并过 没有指向前的指针
        block->size_ += next->size_;
        block->before_ = next->before_;
        block->before_->next_ = block;
        block->next_ = next->next_;
        block->next_->before_ = block;
        Point_back_create(block);
        Point_back_create(block->before_);
        Point_back_create(block->next_);
      }
    }else{
      next = nullptr;
    }
  }

  if(next == nullptr && before == nullptr){ //如果前后都被占用 则从链表中寻找可用连接
    if(free_block_number_ == 0){ //如果没有空闲节点
      Point_insert(help_point_head_,block);
    }else{
      Memorypool_point* tmp_before = help_point_head_->next_;
      for(size_t count = 1; count < block_number_ && tmp_before < block; ++count) {
        tmp_before = tmp_before->next_;
      }
      if(tmp_before > block){
        Point_insert(tmp_before->before_,block);
      }else{
        Point_insert(tmp_before,block);
      }
    }
    Point_back_create(block);
    if(block->before_->size_ != 0)Point_back_create(block->before_);
    if(block->next_->size_ != 0)Point_back_create(block->next_);
    ++free_block_number_;
  }
};
void Memorypool::Free_memory_locked(void* paddress){
  if(paddress < pmemory_data_ || paddress > (to_char(pmemory_data_) + memory_pool_data_size_)) [[unlikely]] {
    NT_LOG_ERROR << "free memory 越界" << NT_LOG_ENDL;
    return;
  }

  Memorypool_point* block = to_memptr(Change_data_to_block(paddress));

  Memorypool_point* before = nullptr;
  Memorypool_point* next = nullptr;

  mutex_.Lock();
  if(block != pmemory_pool_){ //如果不是队首 则有上一个节点
    before = to_memptr(to_char(block) - MEMORY_POOL_POINT_SIZE); //前一个节点尾部信息
    if(before->before_ != nullptr){ //如果前一个节点可以合并
      before = to_memptr(to_char(block) - (before->size_ >> block_size_move_)*MEMORY_POOL_POINT_SIZE);//头
      before->size_ += block->size_;
      block = before;
      Point_back_create(block);
    }else{
      before = nullptr;
    }
  }

  if(to_char(paddress) + block->size_ != pmemory_data_end_){ //如果不是最后一个
    next = to_memptr(to_char(block) + (block->size_ >> block_size_move_) * MEMORY_POOL_POINT_SIZE); //后一个节点信息
    if(next->next_ != nullptr){ //如果后一个节点可以合并 且不是帮助节点
      if(block->before_ != nullptr) { //如果和前一个节点合并过了 记录块整理好了
        block->size_ += next->size_;
        block->next_ = next->next_;
        block->next_->before_ = block;
        Point_back_create(block);
        Point_back_create(block->next_); //修改后面节点的尾部数据块 当后面节点不是帮助节点的时候
        --free_block_number_;
      }else{ //如果没有合并过 没有指向前的指针
        block->size_ += next->size_;
        block->before_ = next->before_;
        block->before_->next_ = block;
        block->next_ = next->next_;
        block->next_->before_ = block;
        Point_back_create(block);
        Point_back_create(block->before_);
        Point_back_create(block->next_);
      }
    }else{
      next = nullptr;
    }
  }

  if(next == nullptr && before == nullptr){ //如果前后都被占用 则从链表中寻找可用连接
    if(free_block_number_ == 0){ //如果没有空闲节点
      Point_insert(help_point_head_,block);
    }else{
      Memorypool_point* tmp_before = help_point_head_->next_;
      for(size_t count = 1; count < block_number_ && tmp_before < block; ++count) {
        tmp_before = tmp_before->next_;
      }
      if(tmp_before > block){
        Point_insert(tmp_before->before_,block);
      }else{
        Point_insert(tmp_before,block);
      }
    }
    Point_back_create(block);
    if(block->before_->size_ != 0)Point_back_create(block->before_);
    if(block->next_->size_ != 0)Point_back_create(block->next_);
    ++free_block_number_;
  }
  mutex_.Unlock();
};

void* Memorypool::Change_block_to_data(Memorypool_point* address){
  return ((to_char(address) - to_char(pmemory_pool_)) / MEMORY_POOL_POINT_SIZE) *
  block_size_ + to_char(pmemory_data_);
};
void* Memorypool::Change_data_to_block(void* address){
  return ((to_char(address) - to_char(pmemory_data_)) >> block_size_move_) *
  MEMORY_POOL_POINT_SIZE + to_char(pmemory_pool_);
};
void Memorypool::Point_insert(Memorypool_point* pbefore,Memorypool_point* pmemory_pool_point){
  pmemory_pool_point->next_ = pbefore->next_;
  pmemory_pool_point->before_ = pbefore;
  pbefore->next_ = pmemory_pool_point;
  pmemory_pool_point->next_->before_ = pmemory_pool_point;
};
void Memorypool::Point_cut(Memorypool_point* pmemory_pool_point){
  pmemory_pool_point->next_->before_ = pmemory_pool_point->before_;
  pmemory_pool_point->before_->next_ = pmemory_pool_point->next_;
  pmemory_pool_point->before_ = nullptr;
  pmemory_pool_point->next_ = nullptr;
};
Memorypool_point* Memorypool::Point_create(void* paddress,const size_t size){
  Memorypool_point* pback_pool_point = to_memptr((to_char(paddress) +
                                                  (size >> block_size_move_) *
                                                  MEMORY_POOL_POINT_SIZE -
                                                  MEMORY_POOL_POINT_SIZE)); //要包括的记录块的最后一个
  //把这一整块记录块最前面和最后面记录成占用
  pback_pool_point->size_ = size;
  pback_pool_point->next_ = nullptr;
  pback_pool_point->before_ = nullptr;
  Memorypool_point* pmemory_pool_point = to_memptr(paddress); //头point
  pmemory_pool_point->size_ = size;
  pmemory_pool_point->next_ = nullptr;
  pmemory_pool_point->before_ = nullptr;
  return pmemory_pool_point;
};
void Memorypool::Point_back_create(Memorypool_point* paddress){
  Memorypool_point* pback_pool_point = to_memptr((to_char(paddress) +
                                              (paddress->size_ >> block_size_move_) *
                                              MEMORY_POOL_POINT_SIZE -
                                              MEMORY_POOL_POINT_SIZE));
  pback_pool_point->size_ = paddress->size_;
  pback_pool_point->next_ = paddress->next_;
  pback_pool_point->before_ = paddress->before_;
};

} // namespace net_tools::base